package com.example.personalizededucationsystem.service;

import com.example.personalizededucationsystem.dto.dto.UpdateUserRequestDto;
import com.example.personalizededucationsystem.dto.dto.UserDetailResponseDto;
import com.example.personalizededucationsystem.dto.request.FileRequest;
import com.example.personalizededucationsystem.dto.request.UpdateNickNameRequest;
import com.example.personalizededucationsystem.dto.request.UpdateUserPasswordRequest;
import com.example.personalizededucationsystem.dto.response.UpdateProfileResponse;
import com.example.personalizededucationsystem.dto.response.UploadFileResponse;
import com.example.personalizededucationsystem.model.User;
import com.example.personalizededucationsystem.repository.UserRepository;
import jakarta.persistence.EntityNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@Service
public class UserService {

    private static final String UPLOAD_DIR = "D:/software-design-I/images/";
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;

    @Autowired
    public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
    }

    public List<UserDetailResponseDto> findAllUsers() {
        return userRepository.findAll().stream()
                .map(UserDetailResponseDto::fromEntity)
                .collect(Collectors.toList());
    }

    public User findUserById(Long userId) {
        return userRepository.findById(userId)
                .orElseThrow(() -> new EntityNotFoundException("用户未找到, ID: " + userId));
    }

    @Transactional
    public User updateUser(Long userId, UpdateUserRequestDto request) {
        User userToUpdate = findUserById(userId);

        User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (currentUser.getUserId().equals(userToUpdate.getUserId()) && request.getIsActive() != null && !request.getIsActive()) {
            throw new IllegalArgumentException("不能禁用自己的账户");
        }
        if (request.getRole() != null) {
            userToUpdate.setRole(request.getRole());
        }
        if (request.getIsActive() != null) {
            userToUpdate.setActive(request.getIsActive());
        }
        if (request.getSubscription() != null) {
            userToUpdate.setSubscription(request.getSubscription());
        }
        return userRepository.save(userToUpdate);
    }

    public UpdateProfileResponse updateNickName(UpdateNickNameRequest request) {
        String currentUsername = SecurityContextHolder.getContext().getAuthentication().getName();
        User user = userRepository.findByUsername(currentUsername).orElseThrow(() -> new EntityNotFoundException("Current user not found"));
        user.setNickname(request.getNewNickname());
        userRepository.save(user);

        return new UpdateProfileResponse("Change UserName Success, New UserName: " + request.getNewNickname());
    }

    public UpdateProfileResponse updateUserPassword(UpdateUserPasswordRequest request) {
        String currentUsername = SecurityContextHolder.getContext().getAuthentication().getName();
        User user = userRepository.findByUsername(currentUsername).orElseThrow(() -> new EntityNotFoundException("User not found"));
        if (!passwordEncoder.matches(request.getPassword(), user.getPassword())) {
            throw new IllegalArgumentException("Current password is incorrect");
        }

        user.setPassword(passwordEncoder.encode(request.getNewPassword()));
        userRepository.save(user);

        return new UpdateProfileResponse("Password updated successfully");
    }

    public UserDetailResponseDto getUserProfile() {
        String currentUsername = SecurityContextHolder.getContext().getAuthentication().getName();
        User user = userRepository.findByUsername(currentUsername).orElseThrow(() -> new EntityNotFoundException("User not found"));
        return UserDetailResponseDto.fromEntity(user);
    }

    public UpdateProfileResponse updateAvatar(FileRequest request, User user) {
        user.setAvatar(request.fileUrl());
        userRepository.save(user);
        return new UpdateProfileResponse("update success");
    }

    public UpdateProfileResponse updateBackground(FileRequest request, User user) {
        if (user.getSubscription().equals(User.Subscription.PREMIUM)) {
            user.setBackgroundUrl(request.fileUrl());
            userRepository.save(user);
            return new UpdateProfileResponse("update success");
        }
        throw new IllegalArgumentException("no access");
    }


    public UploadFileResponse handleFilesUpload(MultipartFile file) {
        String currentUsername = SecurityContextHolder.getContext().getAuthentication().getName();
        userRepository.findByUsername(currentUsername).orElseThrow(() -> new EntityNotFoundException("Current user not found"));

        if (file.isEmpty()) {
            throw new IllegalArgumentException("File is empty");
        }
        try {
            Path uploadPath = Paths.get(UPLOAD_DIR);
            if (!Files.exists(uploadPath)) {
                Files.createDirectories(uploadPath);
            }
            String filename = UUID.randomUUID() + "_" + file.getOriginalFilename();
            Path savePath = Paths.get(UPLOAD_DIR, filename);
            Files.copy(file.getInputStream(), savePath, StandardCopyOption.REPLACE_EXISTING);
            String accessUrl = "/images/" + filename;
            return new UploadFileResponse(accessUrl, filename);
        } catch (IOException e) {
            throw new RuntimeException("Image upload failed", e);
        }
    }
}